package cmd

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/spf13/cobra"
	"github.com/wutianze/nats.go"
	"gluenet/cmd/glue-srvm/app"
	config "gluenet/configs"
	"gluenet/internal/glue-srvm/pkg/gluelog"
	"gluenet/pkg/database/mysql"
	"os"
	"os/signal"
	"syscall"
	"time"
)

var (
	cfgFile string
)

var rootCmd = &cobra.Command{
	Use:   "glue-mquery",
	Short: "glue mquery system",
	Long:  "glue mquery system",
	Run: func(cmd *cobra.Command, args []string) {
		application := app.NewApplication()
		if config.GetConfig().Debug {
			gin.SetMode(gin.DebugMode)
		}
		// Middleware configuration
		application.Use(gin.Recovery(), app.TraceMiddleware(), app.LoggerMiddleware(), app.ErrorMiddleware())
		// Route registration
		app.RegisterRouter(application)
		if err := application.Run(fmt.Sprintf(":%s", config.GetConfig().HttpPort)); err != nil {
			gluelog.Error(err)
		}
		go func() {
			if err := application.Run(fmt.Sprintf(":%s", config.GetConfig().HttpPort)); err != nil {
				gluelog.Errorf("application error: %+v", err)
				os.Exit(1)
			}
		}()
		// Exit
		term := make(chan os.Signal, 1)
		signal.Notify(term, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
		for {
			select {
			case <-term:
				gluelog.Infof("application stop begin...")
				destroy(application)
				gluelog.Infof("application stop end")
				return
			case <-time.After(1 * time.Second):
			}
		}
	},
}

func Execute() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "yaml config file")
}

// Initialize required objects
func initConfig() {
	gluelog.Infof("config init...")
	gluelog.Infof("config file: %s", cfgFile)
	if cfgFile == "" {
		panic("config file is nil")
	}

	// Initialize configuration
	err := config.InitByFilePath(cfgFile)
	if err != nil {
		panic(fmt.Errorf("config init error: %+v", err))
	}
	gluelog.Infof("config init: %+v", config.GetConfig())

	// Initialize nats
	_, err = nats.Connect(config.GetConfig().NatsServerAddr)
	if err != nil {
		gluelog.Errorf("connect nats %v", err)
	}
}

func destroy(app *app.Application) {
	gluelog.Infof("application cancel begin")
	app.Cancel()
	gluelog.Infof("application cancel end")
	gluelog.Infof("mysql close begin")
	db, _ := mysql.GetDB().DB()
	err := db.Close()
	if err != nil {
		gluelog.Infof("db close error")
	}
	gluelog.Infof("mysql close end")
}
